package com.steam.xbcc.service.impl;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.steam.xbcc.constants.RedisSmsConstants;
import com.steam.xbcc.domain.*;
import com.steam.xbcc.dto.PhoneRegisterDto;
import com.steam.xbcc.dto.RedisSmsDto;
import com.steam.xbcc.enums.GlobalExceptionCode;
import com.steam.xbcc.feign.LoginService;
import com.steam.xbcc.mapper.UserMapper;
import com.steam.xbcc.result.JSONResult;
import com.steam.xbcc.service.*;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.util.StringUtils;
import com.steam.xbcc.util.AssertUtil;
import com.steam.xbcc.util.BitStatesUtils;
import com.steam.xbcc.util.QRCodeUtil;
import com.steam.xbcc.util.StrUtils;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Date;

/**
 * <p>
 * 会员登录账号 服务实现类
 * </p>
 *
 * @author wt
 * @since 2022-09-23
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;
    @Autowired
    private IUserAccountService userAccountService;
    @Autowired
    private IUserBaseInfoService userBaseInfoService;
    @Autowired
    private LoginService loginService;
    @Autowired
    private IUserCodeService userCodeService;
    @Autowired
    private IUserIntegralService userIntegralService;

    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public void register(PhoneRegisterDto phoneRegisterDto) {
        //验证电话
        String mobile = phoneRegisterDto.getMobile();
        Integer regChannel = phoneRegisterDto.getRegChannel();
        AssertUtil.isPhone(mobile, GlobalExceptionCode.PHONE_FORMAT_ERROR);
        //验证验证码
        String smsCode = phoneRegisterDto.getSmsCode();
        String redisKey = String.format(RedisSmsConstants.PHONE_BUSINESS_KEY, mobile);
        Object o = redisTemplate.opsForValue().get(redisKey);
        //验证码为空判断
        AssertUtil.isNotNull(o, GlobalExceptionCode.CODE_IS_NULL_ERROR);
        RedisSmsDto redisSmsDto = (RedisSmsDto) o;
        //验证码相同判断
        AssertUtil.isEquals(smsCode, redisSmsDto.getCode(), GlobalExceptionCode.CODE_ERROR);
        User user = selectUser(mobile);
        //判断用户是否存在
        AssertUtil.isNull(user, GlobalExceptionCode.USER_EXISTED_ERROR);
        JSONResult jsonResult = saveLogin(phoneRegisterDto);
        //int i = 1 / 0;
        //判断是否成功
        AssertUtil.isTrue(jsonResult.isSuccess(), GlobalExceptionCode.USER_SAVE_ERROR);
        //判断id是否为null
        AssertUtil.isNotNull(jsonResult.getData(), GlobalExceptionCode.USER_SAVE_ERROR);
        //获取id
        Long id = Long.valueOf(jsonResult.getData().toString());
        Long userId = saveUser(id, phoneRegisterDto);
        initUserAccount(userId);
        // 判断是否使用推荐码
        String reCode = phoneRegisterDto.getCode();
        Long referId = checkCode(reCode);
        initUserBaseInfo(userId, regChannel, referId);
        // 生成该用户的推荐码
        saveUserCode(userId);
        // 判断是否有推荐人，赠送积分你和成长值
        if (referId != null) { // 有推荐人
            // 积分登记
            userIntegralService.integralFromRegister(referId);
            // 记录成长信息
            userBaseInfoService.growScoreFromRegister(referId);
        }


    }

    private Long checkCode(String reCode) {
        if (!StringUtils.isEmpty(reCode)) { // 有推荐码
            Wrapper<UserCode> wrapper = new EntityWrapper<>();
            wrapper.eq("code",reCode);
            wrapper.eq("state",UserCode.CODE_NOT_USED); // 1.验证码存在；2.验证码未使用
            UserCode userCode = userCodeService.selectOne(wrapper);
            // 查询是否存在该条件
            Long referId = userCode.getUserId();
            AssertUtil.isNotNull(userCode,GlobalExceptionCode.REFER_CODE_ERROR);
            userCode.setState(UserCode.CODE_USED); // 修改为已使用
            // 修改使用状态
            Wrapper<UserCode> newWrapper = new EntityWrapper<>();
            newWrapper.eq("user_id", referId);
            userCodeService.update(userCode, newWrapper);
            return referId;
        }
        return null;
    }

    private void saveUserCode(Long userId) {
        UserCode userCode = new UserCode();
        userCode.setUserId(userId);
        userCode.setState(UserCode.CODE_NOT_USED); // 未使用
        // 使用工具类生成推荐码
        String code = StrUtils.getComplexRandomString(4);
        userCode.setCode(code);
        // 生成推荐链接
        String url = null;
        try {
            url = "http://127.0.0.1:6003/reg.phone.html?code=" + code;
            // 生成的二维码的路径及名称
            String destPath = "F:\\IDEA\\workspace\\avalon-wycc\\wycc-ui\\wycc-ui-user\\img\\qrimg\\qr.jpg"+code+".JPG";
            // 生成二维码
            QRCodeUtil.encode(url,null,destPath, true);
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 保存信息
        userCode.setQrUrl(url);
        userCodeService.insert(userCode);
    }

    private void initUserAccount(Long userId) {
        UserAccount userAccount = new UserAccount();
        userAccount.setCreateTime(new Date().getTime());
        userAccount.setPassword("123456");
        userAccount.setId(userId);
        userAccount.setFrozenAmount(new BigDecimal(0));
        userAccount.setUsableAmount(new BigDecimal(0));
        userAccountService.insert(userAccount);
    }

    private void initUserBaseInfo(Long userId, Integer regChannel, Long referId) {
        UserBaseInfo userBaseInfo = new UserBaseInfo();
        userBaseInfo.setId(userId);
        userBaseInfo.setRegChannel(regChannel);
        userBaseInfo.setCreateTime(new Date().getTime());
        userBaseInfo.setReferId(referId);
        userBaseInfoService.insert(userBaseInfo);
    }

    private Long saveUser(Long id, PhoneRegisterDto phoneRegisterDto) {
        User user = new User();
        user.setCreateTime(new Date().getTime());
        user.setLoginId(id);
        user.setNickName(phoneRegisterDto.getMobile());
        user.setPhone(phoneRegisterDto.getMobile());
        long bitState = BitStatesUtils.addState(BitStatesUtils.OP_REGISTED, BitStatesUtils.OP_ACTIVED);
        long state = BitStatesUtils.addState(bitState, BitStatesUtils.OP_AUTHED_PHONE);
        user.setBitState(state);
        insert(user);
        return user.getId();
    }

    private JSONResult saveLogin(PhoneRegisterDto phoneRegisterDto) {
        Login login = new Login();
        login.setUsername(phoneRegisterDto.getMobile());
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        login.setPassword(bCryptPasswordEncoder.encode(phoneRegisterDto.getPassword()));
        login.setType(Login.USER_TYPE);
        login.setEnabled(Login.ENABLE);
        return loginService.saveOrUpdate(login);
    }

    private User selectUser(String mobile) {
        Wrapper<User> wrapper = new EntityWrapper<>();
        wrapper.eq("phone", mobile);
        return selectOne(wrapper);
    }
}
